package com.charles.reflect.test;

import com.charles.reflect.entity.User;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class ReflectDemo {

    public static void main(String[] args) throws Exception {
        List<Integer> list = new ArrayList<Integer>();
        list.add(4);
        list.add(5);
        //list.add("ddd"); 在编译期间，泛型生效，插入字符串对象，则报错
       Class clazz = list.getClass();
        Method method = clazz.getMethod("add", Object.class);
        method.invoke(list,"ddd");
        System.out.println(list);

    }




    /**
     * 无参构造
     * @throws Exception
     */

    public void test1() throws Exception {
        //User类还没加载，在源文件阶段获取字节码文件对象
        Class<?> clazz = Class.forName("com.charles.reflect.entity.User");
        //创建User实例，这里是通过User的无参构造来创建的
        User user = (User)clazz.newInstance();
        System.out.println(user);
    }

    /**
     * 有参构造
     * @throws Exception
     */
    public void test2() throws Exception{
        //获取字节码文件
        Class<?> aClass = Class.forName("com.charles.reflect.entity.User");
        //先获取有参构造器,parameterTypes:表示参数列表，有多少写多少，也可以不写，不写就是调用无参构造
        Constructor<?> constructor = aClass.getConstructor(Integer.class, String.class);
        User user = (User)constructor.newInstance(12, "小明");
    }

    /**
     * 获取全部的构造方法
     * @throws Exception
     */
    public void test3() throws Exception{
        //获取全部构造方法
        Class<?> clazz = Class.forName("com.charles.reflect.entity.User");
        //获取所有的构造方法
        Constructor<?>[] constructors = clazz.getConstructors();
        //遍历所有的构造方法
        for (int i = 0; i < constructors.length; i++) {
            //获取每个构造函数中的参数类型字节码对象
            Class<?>[] parameterTypes = constructors[i].getParameterTypes();
            System.out.println("第"+i+"个构造函数");
            for (int y = 0;  y< parameterTypes.length; ++y) {
                //获取构造函数中参数的类型
                System.out.println(parameterTypes[y].getName()+",");
            }
        }
    }

    public void test4()throws Exception{
        //User类还没加载，在源文件阶段获取字节码文件对象
        Class<?> clazz = Class.forName("com.charles.reflect.entity.User");
        //获取实例对象
        User user = (User)clazz.newInstance();
        //获取成员变量clazz1.getField(name);通过name来获取指定成员变量，
        //如果该成员变量是私有的则应该使用getDeclaredField(name);
        Field field = clazz.getDeclaredField("id");
        //因为属性是私有的，获取属性对象后，还应该打开可见权限
        field.setAccessible(true);
        //赋值操作
        field.set(user,1);
        //获取成员变量的值，field.get(obj);obj为表示字段的值的对象，也就是该属性对应的实例对象
        System.out.println(field.get(user));
    }

    public void test5() throws Exception {
        //获取全部的成员变量
        //User类还没加载，在源文件阶段获取字节码文件对象
        Class<?> clazz = Class.forName("com.charles.reflect.entity.User");
        //创建User实例，这里是通过User的无参构造来创建的
        User user = (User)clazz.newInstance();
        user.setId(1);
        user.setRealName("张三");
        Field[] fields = clazz.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            fields[i].setAccessible(true);
            System.out.println(fields[i].get(user));//获取成员变量的值
        }
    }

    public void test6() throws Exception {
        //User类还没加载，在源文件阶段获取字节码文件对象
        Class<?> clazz = Class.forName("com.charles.reflect.entity.User");
        //创建User实例，这里是通过User的无参构造来创建的
        User user = (User)clazz.newInstance();
        //不带参数的方法，eat为不带参数的public方法
        Method method = clazz.getMethod("eat");

        method.invoke(user);

        //带参数的方法，sing为带一个String类型的参数的方法
        Method method1 = clazz.getMethod("sing", String.class);
        method1.invoke(user,"祝我生日快乐");

        //获取私有的方法和获取私有的属性一样，say为私有方法
        Method method2 = clazz.getDeclaredMethod("say", String.class);
        method2.setAccessible(true);
        method2.invoke(user,"说了一些东西");

        Method[] methods = clazz.getDeclaredMethods();
        User user1 = (User)clazz.newInstance();
        for (Method method3 : methods) {
            method3.setAccessible(true);
            System.out.println(method3.getName());
            //获取方法的参数，又回到之前的代码
            Class<?>[] parameterTypes = method3.getParameterTypes();
            for (int i = 0; i < parameterTypes.length; i++) {
                //获取构造函数中参数的类型
                System.out.println(parameterTypes[i].getName() + ",");
            }
        }

    }
}
